#!/cadtools/programs/perl 

use Env qw(BUILD_TOOLS_PATH);
use lib $BUILD_TOOLS_PATH;

use BuildTool;
use Getopt::Long;
use strict;
use Data::Dumper;



my $first_build; #first build flags
my $buildReport = "buildReport.txt";
my $base_open_wi_allow; #flag related to the open work items
my $base_warn_suppress; #flag related to the compiler and linker warnings
my $type;        #build information
my $prev_type;   #build information
my $conf;        #build information
my $number;      #build information
my %build_file_rev_changes; #polarion file/revisions,status hash
my $build_name = "fw_builds"; #name of the build folder
my $buildInfo = "buildInfo.txt";
my $release_history = "release_history.txt";
my $buildParams = "buildParams.txt";
my $buildParamsPath;
my $project, my $rel_inc;
my $build_file_rev_ref;
my @conf_except = ();

#Get the user command line
getCommand();

#Get the username;
BuildTool->getUsername();
#Delete the BuildTool folder, if exists
system("rm -rf BuildTool");
mkdir("BuildTool");
chdir("BuildTool");
#Read buildParams.txt
$buildParamsPath = "http://cad.medtronic.com/repo/crdm/device/firmware/trunk/tools/build_tool/buildParams/" . $project . ".txt";
$buildParams = VCS->checkOutBuildParams($buildParamsPath);
my $params_ref = BuildTool->readParams($buildParams);
my @params = @$params_ref;


#Initializing variables
my $its_path = $params[0];
my $vcs_path = $params[1];
my $code_dir = $params[2];
my $conf_options_ref = $params[3];
my %conf_options = %$conf_options_ref;

# verify built configuration (Debug, Release, etc.) specified matches 
# one of the following keys.
if(scalar(@conf_except) > 0)
{
	# if in here, then we are building all types except
	# the ones sepcified here - make sure the exceptions
	# are legal values
	for(my $idx=0; $idx<=$#conf_except; $idx++)
	{
		if(!exists($conf_options{$conf_except[$idx]}))
		{
			die "Build configuration \"$conf_except[$idx]\" is not a valid configuration!  Exiting...\n";
		}
	}
}
elsif(!($conf =~ /all/i))
{
	# if in here, we either got one specific configuration - make sure it is valid
	if(!exists($conf_options{$conf}))
	{
		die "Build configuration \"$conf\" is not a valid configuration!  Exiting...\n";
	}
}


#Get the releases history file
BuildTool->getRelHis($vcs_path);

#Create the build report
BuildTool->createBuildReport($buildReport);

#Check if it's the first build;
$first_build = BuildTool->checkIsFirstBuild("tags/$release_history");

if ($first_build eq "false") {
#Get the previous build 
	$prev_type = BuildTool->getPrevBuildName("tags/$release_history",$type);
} elsif ($type eq "cron") {
	die("The first build can't be a cron");
}

#Set build number
$number = BuildTool->defineBuildNumber($first_build,$prev_type,$type);	


#Access polarion and get the work items
BuildTool->accessITS( $its_path, $project, $rel_inc, $type,$base_open_wi_allow,$buildReport);


#Get the file revisions
print "Now searching polairion for file revisions - please wait...(this can take a long time)\n";
my $rev_list_ref = BuildTool->getRevisions(); 
my @rev_list = @$rev_list_ref;

print "Inforamtion from Polarion retrieved - continuing with build process...\n";

#Update build report
BuildTool->updateBuildReportITS();



#The build tool will fail if the build type is a baseline and there's no linked revisions related 
#to the closed work items or if there's no closed work items
if($type eq "baseline" && $rev_list[0] eq ""){
	die "There's no closed work item with code attached";
}

#Get Issue Tracking System (files->revision,status) hash
my $build_file_rev_changes_ref;
my %build_file_rev;
foreach (@rev_list) {
	$build_file_rev_changes_ref = BuildTool->getFileList($_,$vcs_path); 
	%build_file_rev_changes = %$build_file_rev_changes_ref;
}

#If is the first build (and first baseline) there's no previous baseline to get
#the buildInfo file. So the buildInfo hash will be the same as the hash from 
#the issue tracking system.

if($first_build eq "true"){
	%build_file_rev = %$build_file_rev_changes_ref;
	$build_file_rev_ref = \%build_file_rev;
} 
else {
	#Access the repository and get the buildInfo.txt
	BuildTool->getBuildInfo($prev_type,$buildInfo,$vcs_path);
	$build_file_rev_ref = BuildTool->readBuildInfoParams($buildInfo); 
	%build_file_rev = %$build_file_rev_ref;
}

print "\n----------------------------------------\n";
print "              BUILD INFO LIST            \n";
print "\n----------------------------------------\n";
print Dumper( \%build_file_rev );
print "\n----------------------------------------\n";
print "\n            POLARION LIST              \n";
print "\n----------------------------------------\n";
print Dumper( \%build_file_rev_changes );

my %old_build_file_rev = %build_file_rev;
my $old_build_file_rev_ref = \%old_build_file_rev;
#Compare list of files from polarion and from the buildInfo
$build_file_rev_ref = BuildTool->compRevLists($build_file_rev_ref,$build_file_rev_changes_ref,$first_build);

#Compare the updated list from buildInfo and the old list from buildInfo to see if there're changes
if ( ( $type eq "cron" ) && ( $prev_type =~ m/cron/ ) ) {
	BuildTool->checkChangesCrons($build_file_rev_ref,$old_build_file_rev_ref);
}

#Checkout files
BuildTool->checkOut($build_file_rev_ref,$vcs_path);


print "\n--------------------------------------------------------------\n";
print "\n                       BUILDING CODE                          \n";
print "\n--------------------------------------------------------------\n";


#Build code and analyze compiler and linker errors and warnings
#If the build conf is 'All' it will build the code for each configuration except the specified ones
#compare case insensitive
if($conf =~ /^all$/i){
	foreach my $key (keys %conf_options){
		$conf = $key;
		my $build_report_path = $code_dir . "/" . $build_name . "/" . $conf . "/" . $buildReport;
		if(@conf_except) {
			for (my $i = 0; $i < scalar(@conf_except);$i++){					
					if($conf eq $conf_except[$i]){
						delete $conf_options{$conf};
						last;
					} 
			}
		} 
		#Build the configuration if it wasn't deleted because it was an except configuration
		if (exists $conf_options{$conf}) {
			my @conf_number = @{$conf_options{$conf}};
			BuildTool->buildCode($code_dir,$type,$number,$conf_number[0],$conf);
			BuildTool->analyzeCompLinkEW($base_warn_suppress,$build_report_path,$conf, $code_dir . "/code");
		}
		
	}
}
else {
	my $build_report_path = $code_dir . "/" . $build_name . "/" . $conf . "/" . $buildReport;
	my @conf_number = @{$conf_options{$conf}};
	BuildTool->buildCode($code_dir,$type,$number,$conf_number[0],$conf);
	BuildTool->analyzeCompLinkEW($base_warn_suppress,$build_report_path,$conf, $code_dir . "/code/");	
}


#Create the new buildInfo file
print "\n--------------------------------------------------------------\n";
print "\n                    CREATING BUILD INFO                   \n";
print "\n--------------------------------------------------------------\n";
BuildTool->genBuildInfo($code_dir,"trunk",$buildInfo,$vcs_path);

#Tag the build
BuildTool->tagBuild($number);


print "\n--------------------------------------------------------------\n";
print "\n                CREATING NEW REL HISTORY                      \n";
print "\n--------------------------------------------------------------\n";

#update the rel_history file
BuildTool->updateRelHist("tags/$release_history",$type,$number);


###############################################################################
# Function: getCommand
# This subroutine uses the Getopt module and asks the user to specify the command line:
# --type baseline or cron --conf Debug, Release or ReleaseRTLx --project name of the
# project 
# 
# There's also two flags that can be enabled:
# base_warn_suppress and base_open_wi_allow
# The fisrt one ignores the compiler and linker warnings, the seconde one ignores
# the open work items related to the increment
#
# Inputs: String indicating the command line.
# Returns: Nothing
###############################################################################

sub getCommand {
	print "For help: fw_build.pl --help\n";
	my $result = GetOptions(
		'type=s'   => \$type,
		'conf=s'   => \$conf,
		'project=s' => \$project,
		'rel_inc=s' => \$rel_inc,
		'base_warn_suppress' => \$base_warn_suppress,
		'base_open_wi_allow' => \$base_open_wi_allow,
		'help'     => '<>' => \&printUsage
	);
	
	if ( $base_open_wi_allow eq "" ) {
		$base_open_wi_allow = "false";
	} else {
		$base_open_wi_allow = "true";
	}
	if ( $base_warn_suppress eq "" ) {
		$base_warn_suppress = "false";
	}
	else {
		$base_warn_suppress = "true";
	}
	if (
		( ( $type eq "baseline" ) || ( $type eq "cron" ) )
		&& (defined $conf)
		&& (defined $project)
		&& (defined $rel_inc)
	
	  )
	{
		$conf = getAllConfExcept($conf);
		Build->setBuildProper( $type, $conf, $build_name);
	}
	else {
		printUsage();
		exit;
	}
	

}

###############################################################################
# Function: printUsage
# This subroutine is used when the user makes some mistake when typing the 
# command line or when he/she needs some help.
#
# Inputs: Nothing
# Returns: Nothing
###############################################################################
sub printUsage {
        print
"\n-----------------------------------------------------------------------------------------------------\n";
        print "Build Tool Usage:\n\nfw_build.pl --type baseline or cron --conf Debug or Release or ReleaseRTLx or All or All_except_conf or All_except_conf_and_conf --project name of the project --rel_inc increment name\n";
        print
"\n-----------------------------------------------------------------------------------------------------\n";
        print "EXAMPLES:\n\n";
        print "\tfw_build.pl --type baseline --conf Debug --project playground --rel_inc inc1\n";
        print "\tfw_build.pl --type baseline --conf Release --project galaxy --rel_inc inc1 --base_open_wi_allow\n";
        print "\tfw_build.pl --type baseline --conf Debug --project playground --rel_inc inc1 --base_open_wi_allow --base_warn_suppress\n";
        print "\tfw_build.pl --type cron --conf ReleaseRTLx --project playground --rel_inc inc1\n\n";
        print "\tfw_build.pl --type cron --conf All --project playground --rel_inc inc1\n\n";
        print "\tfw_build.pl --type cron --conf All_except_Debug --project playground --rel_inc inc1\n\n";
        print "\tfw_build.pl --type cron --conf All_except_Debug_and_ReleaseRTLx --project playground --rel_inc inc1\n\n";

        print "\nOptions:\n";
        print " --base_warn_suppress   => will enable the build override warnings\n";
        print
          " --base_open_wi_allow   => will enable the closed work items override warnings\n";
}

sub getAllConfExcept
{
	my $conf = $_[0];
	
	if($conf =~ /_except_/)
	{
		my $conf_except = substr($conf,"@+");
		$conf = substr($conf,0,"@-");
		if($conf_except =~ /_and_/)
		{
			@conf_except = split(/_and_/,$conf_except);
		}
		else 
		{
			push(@conf_except,$conf_except);
		}
	}
	return $conf;	
}

